import { BaseChartOptions, BaseChart } from './BaseChart'
import { Path } from '../component/Path'
import { colorPicker } from '../ColorPicker'
import { FontWeight, Text, TextOptions } from '../component/Text'
import { font } from '../Constant'
import { max, sum } from 'd3-array'
import { arc, pie } from 'd3-shape'
import { scaleLinear } from 'd3-scale'
import { timeFormat } from 'd3-time-format'
interface PieChartOptions extends BaseChartOptions {
  radius?: [number, number]
  labelTextStyle?: TextOptions
  showDateLabel?: boolean
  cornerRadius?: number
  padAngle?: number
  minRadio?: number
}
export class PieChart extends BaseChart implements PieChartOptions {
  minRadio: number = 0
  radius: [number, number] = [0, 120]
  cornerRadius: number = 4
  padAngle: number = 5
  keyDurationSec = 0.25
  labelTextStyle: TextOptions = {
    key: 'label-text-style',
    font,
    lineWidth: 6,
    fontSize: 24,
    fontWeight: 'bolder' as FontWeight,
    strokeStyle: '#1e1e1e',
  }

  dateLabel: Text
  showDateLabel: boolean
  constructor (options: PieChartOptions = {}) {
    super(options)
    if (options) {
      Object.assign(this, options)
    }
  }

  getComponent (sec: number) {
    const res = super.getComponent(sec)
    if (this.showDateLabel) {
      const date = this.secToDate(sec)
      const dateLabel = new Text({
        key: 'date-label',
        text: timeFormat(this.dateFormat)(date),
        fillStyle: '#FFF',
        fontSize: 30,
        position: { x: 0, y: 0 },
      })
      res?.children.push(dateLabel)
    }

    const remained = sec % this.keyDurationSec
    const start = sec - remained
    const end = start + this.keyDurationSec
    const comp0 = this.getPieData(start)
    const comp1 = this.getPieData(end)
    const pieData = scaleLinear([start, end], [comp0, comp1])(remained + start)
    const arcGen = arc()
    for (const d of pieData) {
      const path = arcGen
        .endAngle(d.endAngle)
        .padAngle(d.padAngle)
        .startAngle(d.startAngle)
        .innerRadius(this.radius[0])
        .outerRadius(this.radius[1])
        .cornerRadius(this.cornerRadius)
        .padAngle(d.padAngle)({
          innerRadius: 0,
          outerRadius: 0,
          startAngle: 0,
          endAngle: 0,
        })
      const centroid = arcGen.centroid(pieData as any)
      const label = new Text({
        key: `pie-label-${d.data[this.idField] as string}`,
        text: d.data[this.idField],
        fontSize: this.labelTextStyle.fontSize,
        lineWidth: this.labelTextStyle.lineWidth,
        font: this.labelTextStyle.font,
        textAlign: 'center',
        textBaseline: 'middle',
        fillStyle: colorPicker.getColor(d.data[this.idField]),
        fontWeight: this.labelTextStyle.fontWeight,
        strokeStyle: this.labelTextStyle.strokeStyle,
        position: { x: centroid[0], y: centroid[1] },
      })
      const comp = new Path({
        key: `pie-path-${d.data[this.idField] as string}`,
        fillStyle: colorPicker.getColor(d.data[this.idField]),
        strokeStyle: '#0000',
        path,
      })
      res?.children.push(comp)
      res?.children.push(label)
    }
    return res
  }

  private getPieData (sec: number) {
    const currentData = [...this.dataScales.values()].map((scale) => {
      return scale(sec)
    })
    const minRadio = this.minRadio / 360
    const sumValue = sum(currentData, (d) => d[this.valueField])
    const minValue = sumValue * minRadio
    const pieGen = pie()
      .padAngle((Math.PI / 180) * this.padAngle)
      .value((d) => max([d[this.valueField], minValue]))

    currentData.sort((a, b) => {
      if (Number.isNaN(b[this.valueField])) {
        return -1
      } else if (Number.isNaN(a[this.valueField])) {
        return 1
      } else {
        return b[this.idField] - a[this.idField]
      }
    })
    const pieData = pieGen(currentData)

    return pieData
  }
}
